package big

import (
	"mangos/internal/binary"
	"math/big"
	"math/rand"
	"time"
)

// NewInt 创建大数字
func NewInt(x *Int) *Int {
	z := &Int{}
	z.Set(x)
	return z
}

// NewInt64 创建大数字
func NewInt64(x int64) *Int {
	z := &Int{}
	z.SetInt64(x)
	return z
}

// NewUint64 创建大数字
func NewUint64(x uint64) *Int {
	z := &Int{}
	z.SetUint64(x)
	return z
}

// NewBinary 创建大数字（小端序）
func NewBinary(buf []byte) *Int {
	z := &Int{}
	z.SetBinary(buf)
	return z
}

// NewString 创建大数字
func NewString(s string, base int) *Int {
	z := &Int{}
	z.SetString(s, base)
	return z
}

// NewRand 创建大数字
func NewRand(numBytes int) *Int {
	z := &Int{}
	z.SetRand(numBytes)
	return z
}

// Int 整型大数字
type Int struct {
	v big.Int // 值
}

// Int64 获取64位有符号整数
func (z *Int) Int64() int64 { return z.v.Int64() }

// Uint64 获取64位无符号整数
func (z *Int) Uint64() uint64 { return z.v.Uint64() }

// Text 获取指定进制的字符串
func (z *Int) Text(base int) string {
	s := z.v.Text(base)
	if base == 16 && len(s)%2 == 1 {
		return "0" + s
	}
	return s
}

// Binary 获取指定最小长度的二进制串（小端序），长度不足的部分将会填零
func (z *Int) Binary(minSize int) []byte {
	b := z.v.Bytes()
	if minSize > len(b) {
		r := make([]byte, minSize)
		copy(r, b)
	}
	return binary.Flip(b)
}

// SetRand 生成指定字节长度的随机数
func (z *Int) SetRand(numBytes int) *Int {
	buf := make([]byte, numBytes)
	rand.New(rand.NewSource(time.Now().UnixNano())).Read(buf)
	z.v.SetBytes(buf)
	return z
}

// SetString 设置字符串值
func (z *Int) SetString(s string, base int) *Int {
	z.v.SetString(s, base)
	return z
}

// SetInt64 设置64位带符号整数
func (z *Int) SetInt64(x int64) *Int {
	z.v.SetInt64(x)
	return z
}

// SetUint64 设置64位无符号整数
func (z *Int) SetUint64(x uint64) *Int {
	z.v.SetUint64(x)
	return z
}

// SetBinary 设置字节串（小端序）
func (z *Int) SetBinary(buf []byte) *Int {
	b := make([]byte, len(buf))
	copy(b, buf)
	binary.Flip(b)
	z.v.SetBytes(b)
	return z
}

// Set 设置值
func (z *Int) Set(x *Int) *Int {
	z.SetBinary(x.Binary(0))
	return z
}

// Len 获取字节长度
func (z *Int) Len() int {
	bl := z.v.BitLen()
	l := bl / 8
	if bl%8 != 0 {
		l += 1
	}
	return l
}

// ModExp r = z ** x mod y
func (z *Int) ModExp(x *Int, y *Int) (r *Int) {
	r = &Int{}
	r.v.Exp(&z.v, &x.v, &y.v)
	return r
}

// Exp r = z ** x
func (z *Int) Exp(x *Int) (r *Int) {
	r = &Int{}
	r.v.Exp(&z.v, &x.v, nil)
	return r
}

// AddInt64 r = z + x
func (z *Int) AddInt64(x int64) (r *Int) {
	r = &Int{}
	r.v.Add(&z.v, big.NewInt(x))
	return r
}

// Add r = z + x
func (z *Int) Add(x *Int) (r *Int) {
	r = &Int{}
	r.v.Add(&z.v, &x.v)
	return r
}

// SubInt64 r = z - x
func (z *Int) SubInt64(x int64) (r *Int) {
	r = &Int{}
	r.v.Sub(&z.v, big.NewInt(x))
	return r
}

// Sub r = z - x
func (z *Int) Sub(x *Int) (r *Int) {
	r = &Int{}
	r.v.Sub(&z.v, &x.v)
	return r
}

// MulInt64 r = z * x
func (z *Int) MulInt64(x int64) (r *Int) {
	r = &Int{}
	r.v.Mul(&z.v, big.NewInt(x))
	return r
}

// Mul r = z * x
func (z *Int) Mul(x *Int) (r *Int) {
	r = &Int{}
	r.v.Mul(&z.v, &x.v)
	return r
}

// DivInt64 r = z / x
func (z *Int) DivInt64(x int64) (r *Int) {
	r = &Int{}
	r.v.Div(&z.v, big.NewInt(x))
	return r
}

// Div r = z / x
func (z *Int) Div(x *Int) (r *Int) {
	r = &Int{}
	r.v.Div(&z.v, &x.v)
	return r
}

// ModInt64 r = z % x
func (z *Int) ModInt64(x int64) (r *Int) {
	r = &Int{}
	r.v.Mod(&z.v, big.NewInt(x))
	return r
}

// Mod r = z % x
func (z *Int) Mod(x *Int) (r *Int) {
	r = &Int{}
	r.v.Mod(&z.v, &x.v)
	return r
}

// IsZero 判断是否是零
func (z *Int) IsZero() bool {
	return z.v.BitLen() == 0
}
